package com.derbysoft.synxisadapter.dswitch2.translator.impl;

import com.derbysoft.remote.dswitch.core.GenericRQ;
import com.derbysoft.remote.dswitch.core.GenericRS;
import com.derbysoft.remote.dswitch.generic.constants.UniqueIDType;
import com.derbysoft.remote.dswitch.generic.dto.SimpleAmountDTO;
import com.derbysoft.remote.dswitch.generic.dto.UniqueIDDTO;
import com.derbysoft.remote.dswitch.hotel.dto.*;
import com.derbysoft.remote.share.Currency;
import com.derbysoft.synxisadapter.commons.dto.synxis.*;
import com.derbysoft.synxisadapter.commons.exception.SystemException;
import com.derbysoft.synxisadapter.commons.model.Channel;
import com.derbysoft.synxisadapter.commons.model.Hotel;
import com.derbysoft.synxisadapter.commons.repository.HotelRepository;
import com.derbysoft.synxisadapter.dswitch2.translator.Translator;
import org.apache.commons.lang.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class HotelReservationRSTranslatorImpl extends AbstractRQTranslator
        implements Translator<List<OTAHotelResRS>,
        GenericRS<HotelReservationRS>, GenericRQ<HotelReservationRQ>> {
    public static final String SPLIT = ";";
    private HotelRepository hotelRepository;

    @Override
    public GenericRS<HotelReservationRS> translate(List<OTAHotelResRS> rsList, GenericRQ<HotelReservationRQ> rq) {
        return new GenericRS<HotelReservationRS>(null, translatePayload(rsList, rq));
    }

    private HotelReservationRS translatePayload(List<OTAHotelResRS> rsList, GenericRQ<HotelReservationRQ> rq) {
        HotelReservationRS hotelReservationRS = new HotelReservationRS();
        hotelReservationRS.setResStatusType(TransactionStatusConverter.convert(rsList.get(0).getResResponseType()));


        hotelReservationRS.setHotelReservationIDs(
                translateHotelReservationIDs(rq.getPayload().getHotelReservationIDs(), rsList));

        Hotel hotel = hotelRepository.findByPassport(
                rq.getPayload().getHotelReservation().getHotelRef().getCode(), Hotel.Status.ENABLED);

        hotelReservationRS.setOriginalProvider(translateOriginalProvider(hotel));
        hotelReservationRS.setOriginalBuyer(rq.getPayload().getOriginalBuyer());
        hotelReservationRS.setHotelReservation((HotelReservationDTO) rq.getPayload().getHotelReservation().clone());
        Channel channel = findChannel(rq.getHeader().getSource().getUniqueID());
        RoomRate roomRate = rsList.get(0).getHotelReservations().getHotelReservation().get(0).getRoomStays()
                .getRoomStay().get(0).getRoomRates().getRoomRate().get(0);
        hotelReservationRS.getHotelReservation().getRoomStays().get(0).setRoomRate(createRoomRateDTO(roomRate, channel));
        TotalDTO total = translateTotal(rsList);
        hotelReservationRS.setTotal(total);
        for (OTAHotelResRS otaHotelResRS : rsList) {

            HotelReservation hotelReservation = otaHotelResRS.getHotelReservations().getHotelReservation().get(0);
            ReservationRoomStayDTO reservationRoomStayDTO = findRoomStay(
                    hotelReservationRS.getHotelReservation().getRoomStays(),
                    hotelReservation.getRoomStays().getRoomStay().get(0));
            reservationRoomStayDTO.setTotal(total);
        }
        return hotelReservationRS;
    }

    private TotalDTO translateTotal(List<OTAHotelResRS> rsList) {
        BigDecimal amountBeforeTax = BigDecimal.ZERO;
        BigDecimal amountAfterTax = BigDecimal.ZERO;
        HotelReservation hotelReservation = rsList.get(0).getHotelReservations().getHotelReservation().get(0);
        amountBeforeTax = amountBeforeTax.add(
                hotelReservation.getResGlobalInfo().getTotal().getAmountBeforeTax());
        amountAfterTax = amountAfterTax.add(
                hotelReservation.getResGlobalInfo().getTotal().getAmountAfterTax());
        String currencyCode = hotelReservation.getResGlobalInfo().getTotal().getCurrencyCode();

        TotalDTO totalDTO = new TotalDTO();
        totalDTO.setPureAmount(translateSimpleAmount(amountBeforeTax, currencyCode));
        totalDTO.setTotalAmount(translateSimpleAmount(amountAfterTax, currencyCode));
        totalDTO.setTax(translateSimpleAmount(amountAfterTax.subtract(amountBeforeTax), currencyCode));
        return totalDTO;
    }

    private ReservationRoomStayDTO findRoomStay(List<ReservationRoomStayDTO> roomStays, RoomStay roomStay) {
        RatePlan ratePlan = roomStay.getRatePlans().getRatePlan().get(0);
        RoomType roomType = roomStay.getRoomTypes().getRoomType().get(0);

        for (ReservationRoomStayDTO reservationRoomStayDTO : roomStays) {

            if (reservationRoomStayDTO.getRatePlanCode().equals(ratePlan.getRatePlanCode()) &&
                    reservationRoomStayDTO.getRoomTypeCode().equals(roomType.getRoomTypeCode())) {
                return reservationRoomStayDTO;
            }
        }
        String message = String.format("RoomType[%s] RateType[%s] miss match",
                roomType.getInvBlockCode(), ratePlan.getRatePlanCode());
        throw new SystemException(message);
    }

    private UniqueIDDTO translateOriginalProvider(Hotel hotel) {
        UniqueIDDTO uniqueIDDTO = new UniqueIDDTO(hotel.getProviderPassport(), UniqueIDType.GROUP);
        uniqueIDDTO.setCompanyName(hotel.getProviderName());
        return uniqueIDDTO;
    }

    private SimpleAmountDTO translateSimpleAmount(BigDecimal amount, String currencyCode) {
        return new SimpleAmountDTO(TranslateHelper.setScale(amount), Currency.fromCode(currencyCode));
    }

    private List<HotelReservationIDDTO> translateHotelReservationIDs(List<HotelReservationIDDTO> hotelReservationIDs,
                                                                     List<OTAHotelResRS> otaHotelResRSs) {
        ArrayList<HotelReservationIDDTO> hotelReservationIDDTOs = new ArrayList<HotelReservationIDDTO>(hotelReservationIDs);
        HotelReservationIDDTO hotelReservationIDDTO = translateHotelReservationID(otaHotelResRSs);
        if (hotelReservationIDDTO != null) {
            hotelReservationIDDTOs.add(hotelReservationIDDTO);
        }
        return hotelReservationIDDTOs;
    }

    private HotelReservationIDDTO translateHotelReservationID(List<OTAHotelResRS> otaHotelResRSs) {
        StringBuilder builder = new StringBuilder();
        for (OTAHotelResRS otaHotelResRS : otaHotelResRSs) {
            HotelReservation hotelReservation = otaHotelResRS.getHotelReservations().getHotelReservation().get(0);
            if (hotelReservation.getUniqueID() != null) {
                builder.append(hotelReservation.getUniqueID().getID()).append(SPLIT);
            }
        }

        String resIds = StringUtils.removeEnd(builder.toString(), SPLIT);
        if (StringUtils.isNotBlank(resIds)) {
            return new HotelReservationIDDTO(UniqueIDType.HOTEL, resIds);
        }
        return null;
    }


    public void setHotelRepository(HotelRepository hotelRepository) {
        this.hotelRepository = hotelRepository;
    }
}
